package com.jy.framework.dto;

import java.util.*;
import java.util.stream.Collectors;

public class TreeMapDTO extends HashMap {
    private static final long serialVersionUID = 1L;

    public static final String ID = "id";
    public static final String PID = "parent_id";
    public static final String SORT = "order_num";
    public static final String CHILDREN = "subCategories";
    public static final String PARENT_NAME = "parent_name";
    public static final String NAME = "name";
    public static final String ICON = "icon";
    public static final String ROOT = "根目录";

    public static List<Map<String, Object>> createTree(Long pid, Set<Map<String, Object>> list) {
        Map<Long, List<Map<String, Object>>> map = groupList(list);
        return toTree(pid, map);
    }

    private static List<Map<String, Object>> toTree(Long pid, Map<Long, List<Map<String, Object>>> map) {
        return Optional.ofNullable(map.get(pid)).orElseGet(() -> new ArrayList<>()).stream().filter(x -> x.get(PID).equals(pid)).sorted(Comparator.comparing(x -> ((Long) x.get(SORT)))).map(x -> {
            return treeNodeMap(x, toTree((Long) x.get(ID), map));
        }).collect(Collectors.toList());
    }

    private static Map<Long, List<Map<String, Object>>> groupList(Set<Map<String, Object>> list) {
        Map<Object, Map<String, Object>> map = list.stream().collect(Collectors.toMap(key -> key.get(ID), value -> value));
        return list.stream().map(node -> {
            Map<String, Object> objectMap = map.get(node.get(PID));
            Object value = ROOT;
            if (objectMap != null) {
                value = objectMap.get(NAME);
            }
            node.put(PARENT_NAME, value);
            return node;
        }).collect(Collectors.groupingBy(parent -> Long.valueOf(String.valueOf(parent.get(PID)))));
    }

    private static Map<String, Object> treeNodeMap(Map<String, Object> treeNode, List<Map<String, Object>> children) {
        Map<String, Object> node = new HashMap<>();
        node.putAll(treeNode);
        node.put(CHILDREN, children);
        return node;
    }
}
